const path = require('path');
const fs = require('fs');

const lineByLine = require('n-readlines');
const { filesize } = require('filesize');
const libqqwry = require('lib-qqwry');
const qqwry = libqqwry(true, __dirname + "/qqwry.dat");
const _ = require('lodash');
const dayjs = require('dayjs');
const term = require('terminal-kit').terminal;


let safe_address = [
    '本机地址',
    // '阿里',
    // '华为',
    // 'Microsoft',
    // 'Google',
    // 'Amazon',
];

let danger_address = [
    'CZ88.NET',
    '数据中心',
    '法国',
    '华数',
    'Cogent',
    '荷兰',
    '俄罗斯',
    '德国',
    '罗马尼亚',
    '波兰',
    '保加利亚',
    '英国',
    '加拿大',
    '捷克',
    '巴林',
    '澳大利亚',
    '台湾',
];


//https://blog.csdn.net/weixin_51311218/article/details/127013355
function get_ips(str) {
    let reg = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/g
    let array = str.match(reg);

    if (!array) return [];

    return array;
}

function get_ip(str) {
    let reg = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/g
    let array = str.match(reg);

    if (!array) return '';

    return array[0];
}

function get_address(ip) {
    try {
        let result = qqwry.searchIP(ip);
        if (typeof (result.Country) != 'undefined' && typeof (result.Area) != 'undefined') {
            return result.Country + result.Area;
        } else {
            return '';
        }
    } catch (e) {
        return '';
    }
}

function get_is_safe(address) {
    let result = false;
    for (let d of safe_address) {
        if (address.indexOf(d) > -1) {
            result = true;
            break;
        }
    }
    return result;
}

function get_is_danger(address) {
    let result = false;
    for (let d of danger_address) {
        if (address.indexOf(d) > -1) {
            result = true;
            break;
        }
    }
    return result;
}

function to_screen(rows) {
    let tableCells = [
        ['No.', 'ip', '地址', '次数'],
    ];

    for (let [index, row] of rows.entries()) {
        tableCells.push([
            index + 1,
            row.ip,
            row.address,
            row.count,
        ]);
    }
    let options = {
        hasBorder: false,
        contentHasMarkup: true,
        borderChars: 'lightRounded',
        borderAttr: { color: 'blue' },
        textAttr: { bgColor: 'default' },
        firstCellTextAttr: { bgColor: 'blue' },
        firstRowTextAttr: { bgColor: 'yellow' },
        firstColumnTextAttr: { bgColor: 'red' },
        width: 150,
        fit: false   // Activate all expand/shrink + wordWrap
    };
    term.table(tableCells, options);
}

async function to_html(html_file, rows) {
    let content = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ip分析结果</title>
<style>
body{
	font-size:18px;
	line-height:30px;
}
table{
	border-collapse:collapse;
	border:1px solid skyblue;
}
</style>
</head>
<body>
<h2 style="text-align:center;">ip分析结果</h2>

<table width="100%" border="1" align="center">
  <tbody>
    <tr>
      <td>No.</td>
      <td>ip</td>
      <td>地址</td>
      <td>次数</td>
      <td>文本</td>
    </tr>
    ${rows.map((v, k) => {
        let is_danger = get_is_danger(v.address);
        return `
        <tr bgcolor="${is_danger ? '#FF9966' : ''}">
        <td>${k + 1}</td>
        <td><a href="https://www.ip138.com/iplookup.php?ip=${v.ip}&action=2" target="_blank">${v.ip}</td>
        <td>${v.address}</td>
        <td>${v.count}</td>
        <td><textarea rows="10" cols="120">${v.content}</textarea></td>
      </tr>
        `;
    }).join('')}
    
  </tbody>
</table>

</body>
</html>    
`;
    await fs.promises.writeFile(html_file, content, { encoding: 'utf8' });

    return true;
}

async function start() {
    let arguments = process.argv;

    if (typeof (arguments[2]) == 'undefined') {
        console.log('请输入文件名');
        console.log('node index.js 1.log');
        process.exit();
        return;
    }

    try {
        let START_TIME = dayjs().unix();

        let file = arguments[2];
        let stat = await fs.promises.stat(file);
        console.log('文件大小：', filesize(stat.size, { standard: "jedec" }));
        console.log('正在分析中...');

        let IPS = [];

        const liner = new lineByLine(file);

        let line;

        let _n = 0;
        while (line = liner.next()) {
            //最多分析100000行
            if (_n > 100000) {
                break;
            }
            _n++;
            let content = line.toString('ascii');
            /*
            let ips = get_ips(content.substr(0, 50));
            for (let ip of ips) {
                //去掉安全地址
                let address = get_address(ip);
                if (get_is_safe(address)) {
                    continue;
                }
                IPS.push({
                    ip: ip,
                    address: address,
                    count: 1,
                    content: content,
                });
            }
            */
            let ip = get_ip(content.substr(0, 50));
            if (!ip) continue;
            //去掉安全地址
            let address = get_address(ip);
            if (get_is_safe(address)) {
                continue;
            }
            IPS.push({
                ip: ip,
                address: address,
                count: 1,
                content: content,
            });

        }

        // console.log(IPS);
        //https://www.coder.work/article/3906304
        //https://blog.csdn.net/qq_39998226/article/details/116707510
        let FINAL_IPS = _.reduce(IPS, function (mem, next) {
            let ip = next.ip;
            let existingObj = _.find(mem, function (item) { return item.ip === ip; });

            if (existingObj) {
                existingObj.count++;
                //只保留20条
                if (existingObj.count <= 20) {
                    existingObj.content += `\n\n${next.content}`;
                }

            } else {
                mem.push(_.extend(next, { count: 1 }));
            }
            return mem;
        }, []);

        //过滤count>100
        FINAL_IPS = _.filter(FINAL_IPS, function (o) {
            return o.count > 100;
        });

        //https://blog.csdn.net/Janicecat/article/details/122549602
        FINAL_IPS = _.sortBy(FINAL_IPS, function (o) {
            return -o.count;
        });

        

        let END_TIME = dayjs().unix();

        // console.log(FINAL_IPS);
        to_screen(FINAL_IPS);

        console.log('分析完毕，耗时：', END_TIME - START_TIME, '秒');

        //保存结果
        // let html_file = `${__dirname}/result/${dayjs().format('YYYY-MM-DD-HH:mm:ss')}.html`;
        let html_file = `${__dirname}/result/result.html`;
        await to_html(html_file, FINAL_IPS);

        console.log('结果文件已保存至：', html_file);


    } catch (err) {
        console.error(err);
    }


    process.exit();
}

start();